var algorithm = require("../src/hoeffding")
  , util = require("util")
  , redis = require("redis")
  ;

function hdftSys() {
  var changePrefix = 'hfdt:change';
  var sourcePrefix = 'hfdt:source';
  var evaluatePrefix = 'hfdt:evalutor';
  var mergePrefix = 'hfdt:merger';

  return {
    createTreeNode: function (name) {
      var learner = new algorithm.HoeffdingTreeLearner();
      setTimeout(function () {
        console.log(util.inspect(learner.getTree(), true, Number.MAX_VALUE));
      }, 10000);
      
      var evaluatePublisher = redis.createClient();
      var sourceSubscriber = redis.createClient();
      var changePublisher = redis.createClient();
      var mergeSubscriber = redis.createClient();

      sourceSubscriber.subscribe(sourcePrefix + ':' + name);
      sourceSubscriber.on('message', function (channel, message) {
        var featVec = null;
        if (message[0] == '[') {
          featVec = JSON.parse(message);
        } else {
          featVec = message.split(/,/);
        }
        var label = learner.learn(featVec);
        evaluatePublisher.publish(evaluatePrefix, JSON.stringify({
          featVec: featVec,
          label: label
        }));
      });

      mergeSubscriber.subscribe(mergePrefix);
      mergeSubscriber.on('message', function (treeJSON) {
        var tree = JSON.parse(treeJSON);
        learner.setTree(tree);
      });

      learner.on('splitted', function (treeJSON) {
        changePublisher.publish(changePrefix, treeJSON);
      });

      return this;
    },

    createEvaluateNode: function () {
      var allInstances = 0, correctInstances = 0;

      var resultSubscriber = redis.createClient();
      resultSubscriber.subscribe(evaluatePrefix);
      resultSubscriber.on('message', function (channel, message) {
        var result = JSON.parse(message);

        // update statistics.
        allInstances ++;
        if (result.label == result.featVec[result.featVec.length - 1]) {
          correctInstances ++;
        }

        if (allInstances % 1 === 0) {
          console.log('Correctness: ' + correctInstances + '/' + allInstances);
        }
      });

      return this;
    },

    createMergerNode: function () {
      var changeSubscriber = redis.createClient();
      var mergePublisher = redis.createClient();

      changeSubscriber.subscribe(changePrefix);
      changeSubscriber.on('message', function (tree) {
        mergePublisher.publish(mergePrefix, JSON.stringify(tree));
      });

      return this;
    }
  };
};

hdftSys().createTreeNode('1').createEvaluateNode();

function createDataSet() {
  return [
    ['sunny', 'hot', 'high', false, 'no'],
    ['sunny', 'hot', 'hight', true, 'no'],
    ['overcast', 'hot', 'high', false, 'yes'],
    ['rainy', 'mild', 'high', false, 'yes'],
    ['rainy', 'cool', 'normal', false, 'yes'],
    ['overcast', 'cool', 'normal', true, 'yes'],
    ['sunny', 'cool', 'normal', false, 'yes'],
    ['sunny', 'mild', 'high', false, 'no'],
    ['rainny', 'mild', 'normal', false, 'yes'],
    ['sunny', 'mild', 'normal', true, 'yes'],
    ['overcast', 'mild', 'high', true, 'yes'],
    ['overcast', 'hot', 'normal', false, 'yes'],
    ['rainy', 'mild', 'high', true, 'no']
  ];
}

var client = redis.createClient();
createDataSet().forEach(function (featVec) {
  client.publish('hfdt:source:1', JSON.stringify(featVec));
});

console.log('Runing...');